#include "fuPoint.h"
#include <math.h>
#include <xutility> // std::min/std::max

BEGIN_NAMESPACE_CPPX

fuRect::fuRect(const fuPoint& point1, const fuPoint& point2)
{
    x = point1.x;
    y = point1.y;
    width = point2.x - point1.x;
    height = point2.y - point1.y;

    if (width < 0)
    {
        width = -width;
        x = point2.x;
    }
    width++;

    if (height < 0)
    {
        height = -height;
        y = point2.y;
    }
    height++;
}

fuRect& fuRect::Union(const fuRect& rect)
{
    // ignore empty rectangles: union with an empty rectangle shouldn't extend
    // this one to (0, 0)
    if ( !width || !height )
    {
        *this = rect;
    }
    else if ( rect.width && rect.height )
    {
        int x1 = std::min(x, rect.x);
        int y1 = std::min(y, rect.y);
        int y2 = std::max(y + height, rect.height + rect.y);
        int x2 = std::max(x + width, rect.width + rect.x);

        x = x1;
        y = y1;
        width = x2 - x1;
        height = y2 - y1;
    }
    //else: we're not empty and rect is empty

    return *this;
}

fuRect& fuRect::Inflate(fuCoord dx, fuCoord dy)
{
     if (-2*dx>width)
     {
         // Don't allow deflate to eat more width than we have,
         // a well-defined rectangle cannot have negative width.
         x+=width/2;
         width=0;
     }
     else
     {
         // The inflate is valid.
         x-=dx;
         width+=2*dx;
     }

     if (-2*dy>height)
     {
         // Don't allow deflate to eat more height than we have,
         // a well-defined rectangle cannot have negative height.
         y+=height/2;
         height=0;
     }
     else
     {
         // The inflate is valid.
         y-=dy;
         height+=2*dy;
     }

    return *this;
}

bool fuRect::Contains(int cx, int cy) const
{
    return ( (cx >= x) && (cy >= y)
          && ((cy - y) < height)
          && ((cx - x) < width)
          );
}

bool fuRect::Contains(const fuRect& rect) const
{
    return Contains(rect.GetTopLeft()) && Contains(rect.GetBottomRight());
}

fuRect& fuRect::Intersect(const fuRect& rect)
{
    int x2 = GetRight(),
        y2 = GetBottom();

    if ( x < rect.x )
        x = rect.x;
    if ( y < rect.y )
        y = rect.y;
    if ( x2 > rect.GetRight() )
        x2 = rect.GetRight();
    if ( y2 > rect.GetBottom() )
        y2 = rect.GetBottom();

    width = x2 - x + 1;
    height = y2 - y + 1;

    if ( width <= 0 || height <= 0 )
    {
        width =
        height = 0;
    }

    return *this;
}

bool fuRect::Intersects(const fuRect& rect) const
{
    fuRect r = Intersect(rect);

    // if there is no intersection, both width and height are 0
    return r.width != 0;
}

fuRect& fuRect::operator+=(const fuRect& rect)
{
    *this = *this + rect;
    return *this;
}


fuRect& fuRect::operator*=(const fuRect& rect)
{
    *this = *this * rect;
    return *this;
}


fuRect operator+(const fuRect& r1, const fuRect& r2)
{
    int x1 = std::min(r1.x, r2.x);
    int y1 = std::min(r1.y, r2.y);
    int y2 = std::max(r1.y+r1.height, r2.height+r2.y);
    int x2 = std::max(r1.x+r1.width, r2.width+r2.x);
    return fuRect(x1, y1, x2-x1, y2-y1);
}

fuRect operator*(const fuRect& r1, const fuRect& r2)
{
    int x1 = std::max(r1.x, r2.x);
    int y1 = std::max(r1.y, r2.y);
    int y2 = std::min(r1.y+r1.height, r2.height+r2.y);
    int x2 = std::min(r1.x+r1.width, r2.width+r2.x);
    return fuRect(x1, y1, x2-x1, y2-y1);
}

namespace {
    uint pow2(int x){
        return pow((float)x,2);
    }

    uint pt_dis(fuPoint p1,fuPoint p2){
        double pow_add = pow2(p2.x-p1.x) + pow2(p2.y-p1.y);
        return sqrt(pow_add);
    }
}

uint fuPoint::Distance(fuPoint & pt)
{
    return pt_dis(*this,pt);
}

END_NAMESPACE_CPPX
